# Поведенческий шаблон проектирования ("Посетитель")
# Позволяет добавлять в программу новые операции, не изменяя классы объектов, над которыми эти операции могут выполняться.

import abc
import typing


class IVisitor(metaclass=abc.ABCMeta):
    @abc.abstractmethod
    def visit(self, place: 'IPlace'):
        pass


class IPlace(metaclass=abc.ABCMeta):
    @abc.abstractmethod
    def accept(self, visitor: IVisitor):
        pass


class Zoo(IPlace):
    def accept(self, visitor: IVisitor):
        visitor.visit(self)


class Cinema(IPlace):
    def accept(self, visitor: IVisitor):
        visitor.visit(self)


class Circus(IPlace):
    def accept(self, visitor: IVisitor):
        visitor.visit(self)


class HolidayMaker(IVisitor):
    def __init__(self):
        self.value = ''

    def visit(self, place: IPlace):
        if isinstance(place, Zoo):
            self.value = 'Слон в зоопарке'
        elif isinstance(place, Cinema):
            self.value = 'Кино - Властелин колец'
        elif isinstance(place, Circus):
            self.value = 'Клоун в цирке'


if __name__ == '__main__':
    places: typing.List[IPlace] = [Zoo(), Cinema(), Circus()]
    for place in places:
        visitor = HolidayMaker()
        place.accept(visitor)
        print(visitor.value)

    # Слон в зоопарке
    # Кино - Властелин колец
    # Клоун в цирке
